home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 3.2 / Ham Radio Version 3.2 (Chestnut CD-ROMs)(1993).ISO / packet / n17jsrc / alloc.c < prev    next >
C/C++ Source or Header  |  1991-08-23  |  12KB  |  472 lines

  1. /* memory allocation routines
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  *
  4.  * Adapted from alloc routine in K&R; memory statistics and interrupt
  5.  * protection added for use with net package. Must be used in place of
  6.  * standard Turbo-C library routines because the latter check for stack/heap
  7.  * collisions. This causes erroneous failures because process stacks are
  8.  * allocated off the heap.
  9.  */
  10.  /* Mods by G1EMM , PA0GRI */
  11.  
  12. #include <stdio.h>
  13. #include <dos.h>
  14. #include <alloc.h>
  15. #include "global.h"
  16. #include "proc.h"
  17. #include "cmdparse.h"
  18. #include "mbuf.h"
  19.  
  20. static unsigned long Memfail;    /* Count of allocation failures */
  21. static unsigned long Allocs;    /* Total allocations */
  22. static unsigned long Frees;    /* Total frees */
  23. static unsigned long Invalid;    /* Total calls to free with garbage arg */
  24. static unsigned long Yellows;    /* Yellow alert garbage collections */
  25. static unsigned long Reds;    /* Red alert garbage collections */
  26. static unsigned long Overuse;    /* Total calls to free with overused arg */
  27. static unsigned long Intalloc;    /* Calls to malloc with ints disabled */
  28. static unsigned long Intfree;    /* Calls to free with ints disabled */
  29. static int Memwait;        /* Number of tasks waiting for memory */
  30. unsigned long Availmem;        /* Heap memory, ABLKSIZE units */
  31. static int Garbstate;        /* 0 = normal, 1 = yellow, 2 = red */
  32. static unsigned long Morecores;
  33. static int Efficient = 0;    /* 0 = normal/fast, 1 = effecient/slow */
  34. static int Circular = 0;    /* 0 = linear , 1 = circular */
  35.  
  36. static unsigned long Sizes[16];
  37.  
  38. static int dostat __ARGS((int argc,char *argv[],void *p));
  39. static int dofreelist __ARGS((int argc,char *argv[],void *p));
  40. static int dogarbage __ARGS((int argc,char *argv[],void *p));
  41. static int doibufsize __ARGS((int argc,char *argv[],void *p));
  42. static int donibufs __ARGS((int argc,char *argv[],void *p));
  43. static int dothresh __ARGS((int argc,char *argv[],void *p));
  44. static int dosizes __ARGS((int argc,char *argv[],void *p));
  45. static int doefficient __ARGS((int argc,char *argv[],void *p));
  46. static int docircular __ARGS((int argc,char *argv[],void *p));
  47.  
  48. struct cmds Memcmds[] = {
  49.     "circular",    docircular,    0, 0, NULLCHAR,
  50.     "efficient",    doefficient,    0, 0, NULLCHAR,
  51.     "freelist",    dofreelist,    0, 0, NULLCHAR,
  52.     "garbage",    dogarbage,    0, 0, NULLCHAR,
  53.     "ibufsize",    doibufsize,    0, 0, NULLCHAR,
  54.     "nibufs",    donibufs,    0, 0, NULLCHAR,
  55.     "sizes",    dosizes,    0, 0, NULLCHAR,
  56.     "status",    dostat,        0, 0, NULLCHAR,
  57.     "thresh",    dothresh,    0, 0, NULLCHAR,
  58.     NULLCHAR,
  59. };
  60.  
  61. #ifdef    LARGEDATA
  62. #define    HUGE    huge
  63. #else
  64. #define    HUGE
  65. #endif
  66.  
  67. union header {
  68.     struct {
  69.         union header HUGE *ptr;
  70.         unsigned long size;
  71.     } s;
  72.     long l[2];
  73. };
  74.  
  75. typedef union header HEADER;
  76. #define    NULLHDR    (HEADER HUGE *)NULL
  77.  
  78. #define    ABLKSIZE    (sizeof (HEADER))
  79.  
  80. static HEADER HUGE *morecore __ARGS((unsigned nu));
  81.  
  82. static HEADER Base;
  83. static HEADER HUGE *Allocp = NULLHDR;
  84. static unsigned long Heapsize;
  85.  
  86. #define MARKER        0x766c654bL /* Kelv in reverse */
  87.  
  88. /* Allocate block of 'nb' bytes */
  89. void *
  90. malloc(nb)
  91. unsigned nb;
  92. {
  93.     register HEADER HUGE *p, HUGE *q;
  94.     register unsigned nu;
  95.     int i;
  96.     void (**fp)();
  97.  
  98.     if(!istate())
  99.         Intalloc++;
  100.     /* If memory is low, collect some garbage. If memory is VERY
  101.      * low, invoke the garbage collection routines in "red" mode.
  102.      * The Garbstate == 0 check is to prevent infinite recursion
  103.      * when we're called again by the mbuf_crunch routine.
  104.      */
  105.     if((availmem() < Memthresh) && (Garbstate == 0)){
  106.         if(availmem() < Memthresh/2){
  107.             Garbstate = 2;
  108.             Reds++;
  109.         } else {
  110.             Garbstate = 1;
  111.             Yellows++;
  112.         }
  113.         for(fp = Gcollect;*fp != NULL;fp++)
  114.             (**fp)(Garbstate == 2);
  115.         Garbstate = 0;
  116.     }
  117.     if(nb == 0)
  118.         return NULL;
  119.  
  120.     /* Record the size of this request */
  121.     if((i = log2(nb)) >= 0)
  122.         Sizes[i]++;
  123.     
  124.      /* Round up to full block, then add one for header and one for debug */
  125.  
  126.      nu = ((nb + ABLKSIZE - 1) / ABLKSIZE) + 4;    /* force allcated memory  */
  127.     nu &= 0xfffffffeL;                /* to be on offset 0x0008 */
  128.  
  129.     if ((q = Allocp) == NULLHDR){
  130.         Base.s.ptr = Allocp = q = &Base;
  131.         Base.s.size = 1;
  132.     }
  133.  
  134.     if(Efficient) {
  135.         Allocp = q = &Base;    /* Start at the very beginning again */
  136.     }
  137.  
  138.     for (p = q->s.ptr; ; q = p, p = p->s.ptr){
  139.         if (p->s.size >= nu){
  140.             /* This chunk is at least as large as we need */
  141.             if (p->s.size <= nu + 1){
  142.                 /* This is either a perfect fit (size == nu)
  143.                  * or the free chunk is just one unit larger.
  144.                  * In either case, alloc the whole thing,
  145.                  * because there's no point in keeping a free
  146.                  * block only large enough to hold the header.
  147.                  */
  148.                 q->s.ptr = p->s.ptr;
  149.             } else {
  150.                 /* Carve out piece from end of entry */
  151.                 p->s.size -= nu;
  152.                 p += p->s.size;
  153.                 p->s.size = nu;
  154.             }
  155.             if(Circular)
  156.                 Allocp = q;
  157.             p->s.ptr = p;    /* for auditing */
  158.              p->l[(p->s.size * 2) - 2] = (long)p;    /* debug */
  159.              p->l[(p->s.size * 2) - 1] = MARKER;    /* debug */
  160.             Allocs++;
  161.             Availmem -= p->s.size;
  162.             p++;
  163. #ifdef    LARGEDATA
  164.             /* On the brain-damaged Intel CPUs in
  165.              * "large data" model, make sure the offset field
  166.              * in the pointer we return isn't null.
  167.              * The Turbo C compiler and certain
  168.              * library functions like strrchr() assume this.
  169.              */
  170.             if(FP_OFF(p) == 0){
  171.                 /* Return denormalized but equivalent pointer */
  172.                 return (void *)MK_FP(FP_SEG(p)-1,16);
  173.             }
  174. #endif
  175.             return (void *)p;
  176.         }
  177.         if (p == Allocp && ((p = morecore(nu)) == NULLHDR)){
  178.             Memfail++;
  179.             return NULL;
  180.         }
  181.     }
  182. }
  183. /* Get more memory from the system and put it on the heap */
  184. static HEADER HUGE *
  185. morecore(nu)
  186. unsigned nu;
  187. {
  188.     register char HUGE *cp;
  189.     register HEADER HUGE *up;
  190.  
  191.     Morecores++;
  192.     if ((int)(cp = (char HUGE *)sbrk(nu * ABLKSIZE)) == -1)
  193.         return NULLHDR;
  194.  
  195.     up = (HEADER *)cp;
  196.     up->s.size = nu;
  197.     up->s.ptr = up;    /* satisfy audit */
  198.      up->l[(up->s.size * 2) - 2] = (long)up;        /* satisfy debug */
  199.      up->l[(up->s.size * 2) - 1] = MARKER;        /* satisfy debug */
  200.     free((void *)(up + 1));
  201.     Heapsize += nu*ABLKSIZE;
  202.     Frees--;    /* Nullify increment inside free() */
  203.     return Allocp;
  204. }
  205.  
  206. /* Put memory block back on heap */
  207. void
  208. free(blk)
  209. void *blk;
  210. {
  211.     register HEADER HUGE *p, HUGE *q;
  212.     unsigned short HUGE *ptr;
  213.  
  214.     if(!istate())
  215.         Intfree++;
  216.     if(blk == NULL)
  217.         return;        /* Required by ANSI */
  218.     p = (HEADER HUGE *)blk - 1;
  219.     /* Audit check */
  220.     if(p->s.ptr != p){
  221.         ptr = (unsigned short *)&blk;
  222.         printf("free: WARNING! invalid pointer (%Fp) pc = %04x:%04x proc %s\n",blk,
  223.             ptr[-1],ptr[-2],Curproc->name);
  224.         fflush(stdout);
  225.         Invalid++;
  226.         log(-1,"free: WARNING! invalid pointer (%Fp) pc = %04x:%04x proc %s\n",blk,
  227.             ptr[-1],ptr[-2],Curproc->name);
  228.         return;
  229.     }
  230.      if(p->l[(p->s.size * 2) - 2] != (long)p || p->l[(p->s.size * 2) - 1] != MARKER){
  231.          ptr = (unsigned short *)&blk;
  232.          printf("free: WARNING!! overused buffer (%Fp) pc = %04x:%04x proc %s\n",blk,
  233.              ptr[-1],ptr[-2],Curproc->name);
  234.         fflush(stdout);
  235.          Overuse++;
  236.         log(-1,"free: WARNING!! overused buffer (%Fp) pc = %04x:%04x proc %s\n",blk,
  237.             ptr[-1],ptr[-2],Curproc->name);
  238.          return;
  239.      }
  240.     Availmem += p->s.size;
  241.     /* Search the free list looking for the right place to insert */
  242.     for(q = Allocp; !(p > q && p < q->s.ptr); q = q->s.ptr){
  243.         /* Highest address on circular list? */
  244.         if(q >= q->s.ptr && (p > q || p < q->s.ptr))
  245.             break;
  246.     }
  247.     if(p + p->s.size == q->s.ptr){
  248.         /* Combine with front of this entry */
  249.         p->s.size += q->s.ptr->s.size;
  250.         p->s.ptr = q->s.ptr->s.ptr;
  251.     } else {
  252.         /* Link to front of this entry */
  253.         p->s.ptr = q->s.ptr;
  254.     }
  255.     if(q + q->s.size == p){
  256.         /* Combine with end of this entry */
  257.         q->s.size += p->s.size;
  258.         q->s.ptr = p->s.ptr;
  259.     } else {
  260.         /* Link to end of this entry */
  261.         q->s.ptr = p;
  262.     }
  263.     if(Circular)
  264.         Allocp = q;
  265.     Frees++;
  266.     if(Memwait != 0)
  267.         psignal(&Memwait,0);
  268. }
  269.  
  270. #ifdef    notdef    /* Not presently used */
  271. /* Move existing block to new area */
  272. void *
  273. realloc(area,size)
  274. void *area;
  275. unsigned size;
  276. {
  277.     unsigned osize;
  278.     HEADER HUGE *hp;
  279.     char HUGE *cp;
  280.  
  281.     hp = ((HEADER *)area) - 1;
  282.     osize = (hp->s.size -1) * ABLKSIZE;
  283.  
  284.     free(area);    /* Hopefully you have your interrupts off , Phil. */
  285.     if((cp = malloc(size)) != NULL && cp != area)
  286.         memcpy((char *)cp,(char *)area,size>osize? osize : size);
  287.     return cp;
  288. }
  289. #endif
  290. /* Allocate block of cleared memory */
  291. void *
  292. calloc(nelem,size)
  293. unsigned nelem;    /* Number of elements */
  294. unsigned size;    /* Size of each element */
  295. {
  296.     register unsigned i;
  297.     register char *cp;
  298.  
  299.     i = nelem * size;
  300.     if((cp = malloc(i)) != NULL)
  301.         memset(cp,0,i);
  302.     return cp;
  303. }
  304. /* Version of malloc() that waits if necessary for memory to become available */
  305. void *
  306. mallocw(nb)
  307. unsigned nb;
  308. {
  309.     register void *p;
  310.  
  311.     while((p = malloc(nb)) == NULL){
  312.         Memwait++;
  313.         pwait(&Memwait);
  314.         Memwait--;
  315.     }
  316.     return p;
  317. }
  318. /* Version of calloc that waits if necessary for memory to become available */
  319. void *
  320. callocw(nelem,size)
  321. unsigned nelem;    /* Number of elements */
  322. unsigned size;    /* Size of each element */
  323. {
  324.     register unsigned i;
  325.     register char *cp;
  326.  
  327.     i = nelem * size;
  328.     cp = mallocw(i);
  329.     memset(cp,0,i);
  330.     return cp;
  331. }
  332. /* Return available memory on our heap plus available system memory */
  333. unsigned long
  334. availmem()
  335. {
  336.     return Availmem * ABLKSIZE + coreleft();
  337. }
  338.  
  339. /* Print heap stats */
  340. static int
  341. dostat(argc,argv,envp)
  342. int argc;
  343. char *argv[];
  344. void *envp;
  345. {
  346.     tprintf("heap size %lu, avail %lu (%lu%%), morecores %lu, coreleft %lu\n",
  347.      Heapsize,Availmem*ABLKSIZE, 100L*Availmem*ABLKSIZE/Heapsize,Morecores,coreleft());
  348.     tprintf("allocs %lu, frees %lu (diff %lu), alloc fails %lu, invalid frees %lu, overused %lu\n",
  349.         Allocs,Frees,Allocs-Frees,Memfail,Invalid,Overuse);
  350.     tprintf("garbage collections yellow %lu, red %lu\n",Yellows,Reds);
  351.     tprintf("interrupts-off calls to malloc %lu, free %lu\n",Intalloc,Intfree);
  352.     iqstat();
  353.     return 0;
  354. }
  355.  
  356. /* Print heap free list */
  357. static int
  358. dofreelist(argc,argv,envp)
  359. int argc;
  360. char *argv[];
  361. void *envp;
  362. {
  363.     HEADER HUGE *p;
  364.     int i = 0;
  365.  
  366.     for(p = Base.s.ptr;p != &Base;p = p->s.ptr){
  367.         tprintf("%5lx %6lu",ptol((void *)p),p->s.size * ABLKSIZE);
  368.         if(++i == 4){
  369.             i = 0;
  370.             if(tprintf("\n") == EOF)
  371.                 return 0;
  372.         } else
  373.             tprintf(" | ");
  374.     }
  375.     if(i != 0)
  376.         tprintf("\n");
  377.     return 0;
  378. }
  379. static int
  380. dosizes(argc,argv,p)
  381. int argc;
  382. char *argv[];
  383. void *p;
  384. {
  385.     int i;
  386.  
  387.     for(i=0;i<16;i += 4){
  388.         tprintf("N>=%5u:%7ld| N>=%5u:%7ld| N>=%5u:%7ld| N>=%5u:%7ld\n",
  389.          1<<i,Sizes[i],    2<<i,Sizes[i+1],
  390.          4<<i,Sizes[i+2],8<<i,Sizes[i+3]);
  391.     }
  392.     return 0;
  393. }
  394. int
  395. domem(argc,argv,p)
  396. int argc;
  397. char *argv[];
  398. void *p;
  399. {
  400.     return subcmd(Memcmds,argc,argv,p);
  401. }
  402.  
  403. static int
  404. dothresh(argc,argv,p)
  405. int argc;
  406. char *argv[];
  407. void *p;
  408. {
  409.     return setlong(&Memthresh,"Free memory threshold (bytes)",argc,argv);
  410. }
  411.  
  412. static int
  413. donibufs(argc,argv,p)
  414. int argc;
  415. char *argv[];
  416. void *p;
  417. {
  418.     if(setint(&Nibufs,"Interrupt pool buffers",argc,argv) == 0){
  419.         iqclear();
  420.         return 0;
  421.     }
  422.     return 1;
  423. }
  424. static int
  425. doibufsize(argc,argv,p)
  426. int argc;
  427. char *argv[];
  428. void *p;
  429. {
  430.     return setuns(&Ibufsize,"Interrupt buffer size",argc,argv);
  431. }
  432.  
  433. static int
  434. dogarbage(argc,argv,p)
  435. int argc;
  436. char *argv[];
  437. void *p;
  438. {
  439.     void (**fp)();
  440.     int red = 0;
  441.  
  442.     if(argc > 1)
  443.         red = atoi(argv[1]);
  444.  
  445.     if(red)
  446.         Reds++;
  447.     else
  448.         Yellows++;
  449.  
  450.     for(fp = Gcollect;*fp != NULL;fp++)
  451.         (**fp)(red);
  452.     return 0;
  453. }
  454.  
  455. static int
  456. doefficient(argc,argv,p)
  457. int argc;
  458. char *argv[];
  459. void *p;
  460. {
  461.     return setbool(&Efficient,"Efficient/slower mode",argc,argv);
  462. }
  463.  
  464. static int
  465. docircular(argc,argv,p)
  466. int argc;
  467. char *argv[];
  468. void *p;
  469. {
  470.     return setbool(&Circular,"Circular mode",argc,argv);
  471. }
  472.